package com.dynaBlaster.gameElements;

import java.util.ArrayList;
import com.dynaBlaster.BoardView;
import com.dynaBlaster.DynaView;
import com.dynaBlaster.GameConfg;
import com.dynaBlaster.Point;
import com.dynaBlaster.R;
import com.dynaBlaster.DynaView.Area;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;

public class Bomb extends Creature {

	public static final String LOG_TAG = "Bomb";

	private final int STATE_TICKING = 0;
	private final int STATE_EXPLODING = 1;
	private final int STATE_DEAD = 2;

	int state = STATE_TICKING;

	Hero owner;

	int range = GameConfg.BOMB_RANGE;

	long stateStartTime;

	// ranges of explosion effects in directions
	private int range_n, range_s, range_e, range_w;

	private ArrayList<Point> toDestroy = new ArrayList<Point>();

	Bitmap bomb;
	Bitmap expl_centre;
	Bitmap expl_end_n;
	Bitmap expl_end_s;
	Bitmap expl_end_w;
	Bitmap expl_end_e;
	Bitmap expl_middle_vert;
	Bitmap expl_middle_hor;

	public Bomb(DynaView board, long startMilis, Hero hero) {
		super(board);
		this.stateStartTime = startMilis;
		this.owner = hero;
		hero.incrementBombCount();

		speed = 0;
		size = BoardView.mTileSize / 2; // bomba ma staly rozwiar na 1 pole

		Resources r = board.getR();
		bomb = loadImg(r.getDrawable(R.drawable.bomb));
		expl_centre = loadImg(r.getDrawable(R.drawable.bomb_expl));
		expl_end_n = loadImg(r.getDrawable(R.drawable.bomb_expl_up));
		expl_end_s = loadImg(r.getDrawable(R.drawable.bomb_expl_down));
		expl_end_w = loadImg(r.getDrawable(R.drawable.bomb_expl_left));
		expl_end_e = loadImg(r.getDrawable(R.drawable.bomb_expl_right));
		expl_middle_vert = loadImg(r.getDrawable(R.drawable.bomb_expl_mid_vert));
		expl_middle_hor = loadImg(r.getDrawable(R.drawable.bomb_expl_mid_hor));

	}

	public boolean isDead() {
		return state == STATE_DEAD;
	}

	public void updateState(long currentTimeMillis) {
		long time_elapsed = currentTimeMillis - stateStartTime;

		switch (state) {
		case STATE_TICKING:
			if (time_elapsed > GameConfg.BOMB_TICKING_TIME) {
				state = STATE_EXPLODING;
				stateStartTime = System.currentTimeMillis();
				computeExplEffects();
			}
			break;
		case STATE_EXPLODING:
			if (time_elapsed > GameConfg.BOMB_EXPLODING_TIME) {
				state = STATE_DEAD;
				stateStartTime = System.currentTimeMillis();
				destroyWalls();
				owner.decrementBombCount();
			}
			break;
		case STATE_DEAD:
			break;
		}

	}

	private void destroyWalls() {
		for (Point p : toDestroy)
			board.destroyWall(p);
	}

	private void computeExplEffects() {
		{
			int u = BoardView.mTileSize;
			int dist;
			Point next, field;
			ArrayList<Bomb> toDetonate = new ArrayList<Bomb>();

			for (int i = 1; i <= range; i++) {// N

				dist = i * u;
				range_n = i;

				next = new Point(pos.x, pos.y - dist);
				field = BoardView.getBoardCoord(next);
				if (board.getTile(field) == Area.WALL.nr) {
					toDestroy.add(field);
					break;
				} else if (board.getTile(field) == Area.CONCRETE.nr) {
					range_n--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// S

				dist = i * u;
				range_s = i;

				next = new Point(pos.x, pos.y + dist);
				field = BoardView.getBoardCoord(next);
				if (board.getTile(field) == Area.WALL.nr) {
					toDestroy.add(field);
					break;
				} else if (board.getTile(field) == Area.CONCRETE.nr) {
					range_s--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// E

				dist = i * u;
				range_e = i;

				next = new Point(pos.x + dist, pos.y);
				field = BoardView.getBoardCoord(next);
				if (board.getTile(field) == Area.WALL.nr) {
					toDestroy.add(field);
					break;
				} else if (board.getTile(field) == Area.CONCRETE.nr) {
					range_e--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}
			for (int i = 1; i <= range; i++) {// W

				dist = i * u;
				range_w = i;

				next = new Point(pos.x - dist, pos.y);
				field = BoardView.getBoardCoord(next);
				if (board.getTile(field) == Area.WALL.nr) {
					toDestroy.add(field);
					break;
				} else if (board.getTile(field) == Area.CONCRETE.nr) {
					range_w--;
					break;
				} else { // FREE
					Bomb bomb = null;
					// check bombs
					for (Bomb b : board.getBombs())
						if (b.isOverPoint(next)) { // TODO: to bedzie za malo w
													// przypadku latajacych bomb
							bomb = b;
							break;
						}
					if (bomb != null) {
						toDetonate.add(bomb);
						break;
					}
				}
			}

			for (Bomb b : toDetonate) {
				b.nextStateNow();
			}

		}
	}

	private void nextStateNow() {
		stateStartTime = 0;

	}

	@Override
	public void draw(Canvas canvas) {
		int field_corner_x = pos.x - size, field_corner_y = pos.y - size;
		switch (state) {
		case STATE_TICKING:
			canvas.drawBitmap(bomb, field_corner_x, field_corner_y, new Paint());
			break;
		case STATE_EXPLODING:
			canvas.drawBitmap(expl_centre, field_corner_x, field_corner_y, new Paint());

			int u = BoardView.mTileSize;

			// draw ends
			if (range_n > 0)
				canvas.drawBitmap(expl_end_n, field_corner_x, field_corner_y - range_n * u, new Paint());
			if (range_s > 0)
				canvas.drawBitmap(expl_end_s, field_corner_x, field_corner_y + range_s * u, new Paint());
			if (range_e > 0)
				canvas.drawBitmap(expl_end_e, field_corner_x + range_e * u, field_corner_y, new Paint());
			if (range_w > 0)
				canvas.drawBitmap(expl_end_w, field_corner_x - range_w * u, field_corner_y, new Paint());

			// draw explosion middles
			for (int i = 1; i < range_n; i++) {// N
				canvas.drawBitmap(expl_middle_vert, field_corner_x, field_corner_y - i * u, new Paint());
			}
			for (int i = 1; i < range_s; i++) {// S
				canvas.drawBitmap(expl_middle_vert, field_corner_x, field_corner_y + i * u, new Paint());
			}
			for (int i = 1; i < range_e; i++) {// E
				canvas.drawBitmap(expl_middle_hor, field_corner_x + i * u, field_corner_y, new Paint());
			}
			for (int i = 1; i < range_w; i++) {// W
				canvas.drawBitmap(expl_middle_hor, field_corner_x - i * u, field_corner_y, new Paint());
			}

			break;
		case STATE_DEAD:
			break;
		}

	}

	@Override
	public boolean touchesCreature(Creature other) {
		switch (state) {
		case STATE_TICKING:
			return false;
		case STATE_EXPLODING:
			int dX = other.pos.x - pos.x;
			int dY = other.pos.y - pos.y;

			dX = Math.abs(dX);
			dY = Math.abs(dY);

			// horizontal expl touch rect
			if (dX < other.size + this.size + range * BoardView.mTileSize && dY < this.size + other.size)
				return true;
			// vertical expl touch rect
			if (dX < this.size + other.size && dY < other.size + this.size + range * BoardView.mTileSize)
				return true;

			return false;
		case STATE_DEAD:
			return false;
		}

		return false;
	}

	@Override
	public void move() {
		return;
	}

	public Hero getOwner() {
		return owner;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + range;
		result = prime * result + (int) (stateStartTime ^ (stateStartTime >>> 32));
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Bomb other = (Bomb) obj;
		if (range != other.range)
			return false;
		if (stateStartTime != other.stateStartTime)
			return false;
		return true;
	}

}
